package geektime.concurrent.part2.concurrencycontrol;

import java.util.concurrent.*;

/**
 * 使用一些同步控制器控制线程同时运作
 */
public class ThreadStartAtTheSameTimeDemo {
    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        // 使用CountDownLatch来实现线程同时运作
        countDownLatchDemo();
        TimeUnit.MILLISECONDS.sleep(100);

        // 使用CyclicBarrier来实现线程同时运作
        cyclicBarrierDemo();
        TimeUnit.MILLISECONDS.sleep(100);

        // 使用Phaser来实现线程同时运作
        PhaserDemo();
    }

    public static void countDownLatchDemo() throws InterruptedException {
        System.out.println("        >>> 使用 CountDownLatch <<<<");
        // 这里CountDownLatch()传入count的含义：the number of times {@link #countDown} must be invoked
        //  before threads can pass through
        CountDownLatch latch = new CountDownLatch(2);
        // 创建并启动2个线程，将latch传入
        new CountDownLatchWorker("Latch Worker-1", latch).start();
        new CountDownLatchWorker("Latch Worker-2", latch).start();
        // 休眠50ms，确保上面两个线程都已经启动完成
        TimeUnit.MILLISECONDS.sleep(50);
        // 使用latch的countDown()方法
        System.out.println(" 释放 latch:");
        System.out.println("latch 倒计时1次");
        latch.countDown();
        System.out.println("latch 倒计时2次");
        latch.countDown();
    }

    private static void cyclicBarrierDemo() throws InterruptedException, BrokenBarrierException {
        System.out.println("        >>> 使用 CyclicBarrier <<<<");
        // 这里CyclicBarrier()传入parties的含义：当在同一个barrier下调用await()方法的线程数达到parties个时，就同时冲破屏障
        CyclicBarrier barrier = new CyclicBarrier(3);
        // 创建并启动2个线程，将barrier传入
        new Thread(new CyclicBarrierWorker(barrier), "Barrier Worker-1").start();
        new Thread(new CyclicBarrierWorker(barrier), "Barrier Worker-2").start();
        // 休眠50ms，确保上面两个线程都已经启动完成
        TimeUnit.MILLISECONDS.sleep(50);
        // 在主线程下执行barrier.await()发放，让调用await()方法的线程数量等于3
        System.out.println("主线程调用await()方法");
        barrier.await();
    }


    private static void PhaserDemo() throws InterruptedException {
        System.out.println("        >>> 使用 Phaser <<<<");
        // 创建一个Phaser，并让主线程也注册到这个phaser中
        Phaser phaser = new Phaser();
        phaser.register();
        // 创建并启动2个线程
        new PhaserWorker("Phaser Worker-1", phaser).start();
        new PhaserWorker("Phaser Worker-2", phaser).start();
        // 休眠50ms，确保上面两个线程都已经启动完成
        TimeUnit.MILLISECONDS.sleep(50);
        // 在主线程下执行phaser.arriveAndAwaitAdvance()，这样就有3个parties都执行了这个方法，就可以同时冲破屏障
        System.out.println("phaser的总个数=" + phaser.getPhase());
        System.out.println("注册的个数=" + phaser.getRegisteredParties());
        System.out.println("到达的个数=" + phaser.getArrivedParties());
        System.out.println("主线程开始执行arriveAndAwaitAdvance方法");
        phaser.arriveAndAwaitAdvance();
    }
}
